package com.ryx.service.Impl;

import com.ryx.constants.Constant;
import com.ryx.entity.SysPermission;
import com.ryx.exception.GlobalException;
import com.ryx.exception.code.BaseResponseCode;
import com.ryx.mapper.SysPermissionMapper;
import com.ryx.service.PermissionService;
import com.ryx.service.RolePermissionService;
import com.ryx.service.UserRoleService;
import com.ryx.utils.RedisUtil;
import com.ryx.utils.TokenSetting;
import com.ryx.vo.req.PermissionAddReqVo;
import com.ryx.vo.req.PermissionUpdateReqVo;
import com.ryx.vo.resp.PermissionRespNodeVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsPackage: com.ryx.service.Impl
 * @Author: 容永轩
 * @CreateTime: 2020-12-23
 * @Description:
 */
@Service
@Transactional
public class PermissionServiceImpl implements PermissionService {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private TokenSetting tokenSetting;

    @Autowired
    private RedisUtil redisUtil;


    @Override
    public List<SysPermission> selectAll() {
        List<SysPermission> permissionList = sysPermissionMapper.selectAll();

        if ( !permissionList.isEmpty()){
            for (SysPermission sysPermission : permissionList) {
                SysPermission parent = sysPermissionMapper.selectByPrimaryKey(sysPermission.getPid());
                if (parent != null){
                    sysPermission.setPidName(parent.getName());
                }
            }
        }

        return permissionList;
    }

    @Override
    public List<PermissionRespNodeVo> selectAllMenuByTree() {

        List<SysPermission> list =sysPermissionMapper.selectAll();
        List<PermissionRespNodeVo> result = new ArrayList<>();
        PermissionRespNodeVo respNodeVo = new PermissionRespNodeVo();
        respNodeVo.setId("0");
        respNodeVo.setTitle("默认顶级菜单");

        //递归调用
        respNodeVo.setChildren(getTree(list,true));

        result.add(respNodeVo);
        return result;
    }

    //boolean 递归遍历到菜单  true 递归遍历到按钮 false
    private List<PermissionRespNodeVo> getTree(List<SysPermission> all,boolean type){
        List<PermissionRespNodeVo> list = new ArrayList<>();
        if (all.isEmpty()){
            return list;
        }

        for (SysPermission sysPermission : all) {
            //顶级目录 判断是不是0 先组装最上层的数据
            if (sysPermission.getPid().equals("0")){
                PermissionRespNodeVo respNodeVo = new PermissionRespNodeVo();

                BeanUtils.copyProperties(sysPermission,respNodeVo);

                respNodeVo.setTitle(sysPermission.getName());

                if (type){
                    respNodeVo.setChildren(getChildrenExBtn(sysPermission.getId(),all));
                }else{
                    respNodeVo.setChildren(getChild(sysPermission.getId(),all));
                }
                list.add(respNodeVo);
            }
        }
        return list;
    }

    //递归方法 递归到目录和菜单

    /**
     *
     * @param id  这个要新增的系统权限的uuid
     * @param allSys  所有的系统权限
     * @return list
     */
    public List<PermissionRespNodeVo> getChildrenExBtn(String id , List<SysPermission> allSys){

        List<PermissionRespNodeVo> list = new ArrayList<>();
        for (SysPermission allSy : allSys) {
            //list中的data 的父级id必须一致 并且数据类项不能是按钮
            // 因为要归到同一个目录或者菜单下
            if (allSy.getPid().equals(id) && allSy.getType() !=3){
                PermissionRespNodeVo respNodeVo = new PermissionRespNodeVo();

                BeanUtils.copyProperties(allSy,respNodeVo);

                respNodeVo.setTitle(allSy.getName());
                respNodeVo.setChildren(getChildrenExBtn(allSy.getId(),allSys));

                list.add(respNodeVo);
            }
        }
        return list;
    }

    //递归到按钮
    public List<PermissionRespNodeVo> getChild(String id ,List<SysPermission> all){
        List<PermissionRespNodeVo> list=new ArrayList<>();
        for (SysPermission s: all) {
            if(s.getPid().equals(id)){
                PermissionRespNodeVo respNodeVO=new PermissionRespNodeVo();
                BeanUtils.copyProperties(s,respNodeVO);
                respNodeVO.setTitle(s.getName());
                respNodeVO.setChildren(getChild(s.getId(),all));
                list.add(respNodeVO);
            }
        }
        return list;
    }


    @Override
    public SysPermission addPermission(PermissionAddReqVo vo) {

        SysPermission sysPermission = new SysPermission();
        BeanUtils.copyProperties(vo,sysPermission);
        //验证
        verify(sysPermission);

        sysPermission.setId(UUID.randomUUID().toString());
        sysPermission.setCreateTime(new Date());
        int insert = sysPermissionMapper.insertSelective(sysPermission);
        if (insert != 1){
            throw new GlobalException(BaseResponseCode.DATA_ERROR);

        }
        return sysPermission;
    }

    private void verify(SysPermission sysPermission){
        /*
        保存数据的时候需要对父级校验
            操作后的菜单类型是目录的时候 父级必须为目录
            操作后的菜单类型是菜单的时候，父类必须为目录类型
            操作后的菜单类型是按钮的时候 父类必须为菜单类型
         */
        //通过pid拿到父级的实体
        SysPermission parent = sysPermissionMapper.selectByPrimaryKey(sysPermission.getPid());

        switch (sysPermission.getType()){
            case 1:
                if (parent != null){
                    //这里的判断可能是操作后的菜单类型是目录的时它的父级无论如何都是目录 即type=1 ，即便我们的顶级菜单是type是0
                    if (parent.getType()!=1){
                        throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                    }
                }else if (!sysPermission.getPid().equals("0")){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                }
                break;
            case 2:
                if (parent == null || parent.getType()!= 1){
                    throw  new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_MENU_ERROR);
                }
                if (StringUtils.isEmpty(sysPermission.getUrl())){
                    throw  new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                break;
            case 3:
                if(parent==null||parent.getType()!=2){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_BTN_ERROR);
                }
                if(StringUtils.isEmpty(sysPermission.getPerms())){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_PERMS_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getUrl())){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getMethod())){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_METHOD_NULL);
                }
                if(StringUtils.isEmpty(sysPermission.getCode())){
                    throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_URL_CODE_NULL);
                }
                break;
        }


    }


    @Override
    public List<PermissionRespNodeVo> permissionTreeList(String userId) {
        return getTree(getPermissions(userId),true);
    }

    @Override
    public List<PermissionRespNodeVo> selectAllTree() {

        return getTree(selectAll(),false);
    }

    @Override
    public void updatePermission(PermissionUpdateReqVo vo) {

        SysPermission update = new SysPermission();
        BeanUtils.copyProperties(vo,update);
        //验证父级关系
        verify(update);

        //通过id查出真实的数据
        SysPermission sysPermission = sysPermissionMapper.selectByPrimaryKey(vo.getId());

        if (sysPermission ==null){
            throw new GlobalException(BaseResponseCode.DATA_ERROR);
        }

        if (!sysPermission.getPid().equals(vo.getPid()) || !sysPermission.getStatus().equals(vo.getStatus())){
            //判断所属菜单发生变化后 要校验该权限是否存在子集
            List<SysPermission> sysPermissions = sysPermissionMapper.selectChild(vo.getId());
            if (!sysPermissions.isEmpty()){
                throw new GlobalException(BaseResponseCode.OPERATION_MENU_PERMISSION_UPDATE);
            }
        }

        //更新数据
        update.setUpdateTime(new Date());
        int i = sysPermissionMapper.updateByPrimaryKeySelective(update);

        if (i !=1){
            throw new GlobalException(BaseResponseCode.OPERATION_ERROR);
        }

        //判断授权标识符是否发生变化
        if (!sysPermission.getPerms().equals(vo.getPerms()) || sysPermission.getStatus().equals(vo.getStatus())){

            //通过当前修改目录或菜单的id 查询该目录或菜单下的权限子集
            //根据菜单权限id获取关联的角色id集合
            List<String> roleIdsByPermissionId = rolePermissionService.getRoleIdsByPermissionId(vo.getId());

            if (!roleIdsByPermissionId.isEmpty()){
                //通过角色id集合查找用户id集合
                List<String> userIdsByRoleIds = userRoleService.getUserIdsByRoleIds(roleIdsByPermissionId);

                if (!userIdsByRoleIds.isEmpty()){
                    for (String userId : userIdsByRoleIds) {
                        redisUtil.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);

                        //清楚用户授权缓存
                        redisUtil.delete(Constant.IDENTIFY_CACHE_KEY+userId);
                    }
                }
            }
        }




    }

    @Override
    public void deletedPermission(String permissionId) {
        //判断是否有子集关联
        List<SysPermission> sysPermissions = sysPermissionMapper.selectChild(permissionId);
        if (!sysPermissions.isEmpty()){
            throw new GlobalException(BaseResponseCode.ROLE_PERMISSION_RELATION);
        }

        //更新权限数据
        SysPermission sysPermission=new SysPermission();
        sysPermission.setUpdateTime(new Date());
        sysPermission.setDeleted(0);
        sysPermission.setId(permissionId);
        int i = sysPermissionMapper.updateByPrimaryKeySelective(sysPermission);
        if(i!=1){
            throw new GlobalException(BaseResponseCode.OPERATION_ERROR);
        }
        //判断授权标识符是否发生了变化
        List<String> roleIdsByPermissionId = rolePermissionService.getRoleIdsByPermissionId(permissionId);

        //解除相关角色和该菜单权限的关联
        rolePermissionService.removeRoleByPermissionId(permissionId);

        if(!roleIdsByPermissionId.isEmpty()){
            List<String> userIdsByRoleIds = userRoleService.getUserIdsByRoleIds(roleIdsByPermissionId);
            if(!userIdsByRoleIds.isEmpty()){
                for (String userId: userIdsByRoleIds) {
                    redisUtil.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                    /**
                     * 清楚用户授权数据缓存
                     */
                    redisUtil.delete(Constant.IDENTIFY_CACHE_KEY+userId);
                }
            }
        }
    }

    @Override
    public List<String> getPermissionByUserId(String userId) {
        List<SysPermission> permissions = getPermissions(userId);
        if(permissions==null||permissions.isEmpty()){
            return null;
        }
        List<String> result=new ArrayList<>();

        for (SysPermission s: permissions) {
            if(!StringUtils.isEmpty(s.getPerms())){
                //把查到的权限信息中的perms 比如sys:dept:update之类的加到result 中返回
                result.add(s.getPerms());
            }
        }
        return result;
    }

    @Override
    public List<SysPermission> getPermissions(String userId) {
        //在中间表中通过userId 查询角色id集合
        List<String> roleIdsByUserId = userRoleService.getRoleIdsByUserId(userId);

        if(roleIdsByUserId.isEmpty()){
            return null;
        }

        //在sys_role_permission中间表中 通过角色id集合 查询角色拥有的权限id集合
        List<String> permissionIdsByRoleIds = rolePermissionService.getPermissionIdsByRoleIds(roleIdsByUserId);

        if (permissionIdsByRoleIds.isEmpty()){
            return null;
        }
        //再通过查到角色所拥有的权限id集合 在sys_permission表中找到对应的data 返回即可
        List<SysPermission> result=sysPermissionMapper.selectByIds(permissionIdsByRoleIds);

        return result;
    }


}
